#pragma once
#include<iostream>
#include<string>
#include<cstring>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>

#define Convert(addrptr)((struct sockaddr*) addrptr)
namespace Net_Work
{
    const static int defaultsockfd = -1;//默认文件描述符 = -1
    const int backlog = 5;

    enum
    {
        SocketError = 1,
        BindError,
        ListenError
    };
    //封装socket接口类
    //设计模式模板方法类
    class Socket
    {
        public:
        virtual void CreateSocketOrDie() = 0;//创建套接字
        virtual void BindSocketOrDie(uint16_t port) = 0;//绑定网路信息
        virtual void ListenSocketOrDie(int backlog) = 0;//监听套接字
        virtual int AcceptConnection(std::string *peerip,uint16_t *peerport) = 0;//接受链接
        virtual bool connectServer(std::string &serverip,uint16_t serverport) = 0;//连接服务器
        virtual int GetSockFd()=0;//获取文件描述符
        virtual void SetSockFd(int sockfd) = 0;//设置文件描述符
        virtual void CloseSocket() = 0;//关闭套接字
        virtual bool Recv(std::string *buffer,int size) = 0;//套接字的接收缓冲区复制数据到指定的缓冲区中
        virtual void Send(std::string &send_str) = 0;//send发送数据
        virtual void ReUseAddr()=0;//重用地址
        virtual ~Socket(){}
        public:
        void BuildlistenSocketMethod(uint16_t port,int backlog)//建立监听套接字方法
        {
            CreateSocketOrDie();
            ReUseAddr();
            BindSocketOrDie(port);
            ListenSocketOrDie(backlog);
        }
        bool BuildConnectSocketMethod(std::string &serverip,uint16_t serverport)
        {
            CreateSocketOrDie();
            return connectServer(serverip,serverport);
        }
        void BuildNormalSocketMethod(int sockfd)
        {
            SetSockFd(sockfd);
        }
    };
    class Tcpsocket :public Socket
    {
        public:
        Tcpsocket(int sockfd = defaultsockfd)
        :_sockfd(sockfd)
        {}
        void CreateSocketOrDie()override
        {
            _sockfd  = socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
            {
                exit(SocketError);
            }
        }
        void BindSocketOrDie(uint16_t port) override
        {
            //填充struct
            struct sockaddr_in local;//本地
            memset(&local,0,sizeof(local));
            local.sin_family= AF_INET;
            local.sin_addr.s_addr = INADDR_ANY;//服务器应该绑定到所有可用的IP地址上
            local.sin_port = htons(port);
            
            int n = ::bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
            if(n<0)
            {
                exit(BindError);
            }
        }
        void ListenSocketOrDie(int backlog)override
        {
            int n = ::listen(_sockfd,backlog);
            if(n<0)
            {
                exit(ListenError);
            }
        }
        int AcceptConnection(std::string *peerip,uint16_t *peerport) override
        {
            //接收连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int newsockfd= ::accept(_sockfd,Convert(&peer),&len); //在服务器端处理客户端的连接请求
            //当服务器端的套接字处于监听状态，accept函数允许服务器接收进入的连接尝试，accept是阻塞的，
            //如果客户端没有链接，它会一直等待到连接位置
            if(newsockfd<0)
            {
                return -1;
            }
            *peerport = ntohs(peer.sin_port);//网络字节序转换称主机字节序
            *peerip = inet_ntoa(peer.sin_addr);//将网络地址转换成十进制的字符串格式
            return newsockfd;
        }
        bool connectServer(std::string &serverip,uint16_t serverport) override
        {
            struct sockaddr_in server;
            memset(&server,0,sizeof(server));
            server.sin_family = AF_INET;
            server.sin_addr.s_addr = inet_addr(serverip.c_str());//十进制IPV4地址转换成网络字节序列的长整型数数据
            server.sin_port = htons(serverport);
            int n = ::connect(_sockfd,Convert(&server),sizeof(server));//建立网络通信,客户端发起对服务器请求
            if(n==0)
            {
                return true;
            }
            else 
            {
                return false;
            }
        }
        int GetSockFd() override//获取套接字文件描述符
        {
            return _sockfd;
        }
        void SetSockFd(int sockfd) override//设置文件描述符
        {
            _sockfd = sockfd;
        }
        void CloseSocket() override
        {
            if(_sockfd>defaultsockfd)
                ::close(_sockfd);
        }
        bool Recv(std::string *buffer,int size)override
        {
            char inbuffer[size];
            ssize_t n = recv(_sockfd,inbuffer,size-1,0);//读
            if(n>0)
            {
                inbuffer[n] = 0;
                *buffer += inbuffer;
                return true;
            }
            else if(n==0)
            {
                return false;
            }
            else
            {
                return false;
            }
        }
        void Send(std::string &send_str)override
        {
            send(_sockfd,send_str.c_str(),send_str.size(),0);
        }
        void ReUseAddr()override
        {
            int opt = 1;
            setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//常见用途是启用端口复用，允许多个套接字绑定到同一个端口
        }

        private:
        int _sockfd;
    };
}